#include "v-graphs.h"



int HRES =0;
int VRES =0;

long get_address(int mode)
{
	__dpmi_regs regs;
	unsigned long dosbuf, address=0; 
	dosbuf = __tb & 0xFFFFF; /* dosbuf é a área de transferência */
	dosmemput(&address, 4, dosbuf+40); /*apaga bytes 40 a 43 dessa área*/
	regs.x.ax = 0x4F01; /* VBE get mode info */	
	regs.x.di = dosbuf & 0xF; /* LSB da área de transferência */
	regs.x.es = (dosbuf >> 4) & 0xFFFF; /*MSBda área de transferência*/
	regs.x.cx = mode; /*informaçã sobre o modo 105h*/
	__dpmi_int(0x10, &regs); /* DOS int 10h */
	if (regs.h.ah) /* tratamento de erro, modo não suportado */
	{
		printf("MODO NAO SUPORTADO!");
		return -1;
	}
	dosmemget(dosbuf+40, 4, &address); /* lê o endereço da memória vídeo */ 
	if (!address)  /* tratamento de erro, modo não suportado */
	{
		printf("MODO NAO SUPORTADO!");
		return -1;	
	}
	
	return (long)address;
}

char * enter_graphics(int mode, __dpmi_meminfo *map)
{
	__dpmi_regs regs; /*__dpmi_regs é uma estrutura que representaos registos do CPU */ 
	regs.x.ax = 0x4F02; /* registo AX do CPU com valor 0x4f02 */
	regs.x.bx =0x4000+ mode; /* registo BX do CPU com valor 0x4105 */
	__dpmi_int(0x10, &regs); /* gera interrupção de software 0x10, activando o modo gráfico */
	
	
	long addr = get_address(mode);
	if(addr == -1)
	return (char *)NULL;
	
	if(mode == 0x101){HRES = 640; VRES = 480;}
	if(mode == 0x103){HRES = 800; VRES = 600;}
	if(mode == 0x105){HRES = 1024; VRES = 768;}
	if(mode == 0x107){HRES = 1280; VRES = 1024;}
	
	
	
	
	
	__djgpp_nearptr_enable(); 
	map->address = (unsigned long)(addr);
	map->size = HRES * VRES;
	__dpmi_physical_address_mapping(map);
	
	return (char *)(map->address + __djgpp_conventional_base);
}


void leave_graphics(__dpmi_meminfo map)
{
	
	__dpmi_free_physical_address_mapping(&map); /* liberta mapeamento */
	__djgpp_nearptr_disable(); 

	__dpmi_regs regs;
	regs.x.ax = 0x0003; /* registo AX do CPU com valor 0x03 */
	__dpmi_int(0x10, &regs); /* gera interrup ¸c~ao software 0x10, entrando no modo texto */
}


void set_pixel(int x, int y, int color, char *base)
{
	if(!(x > HRES -1 || y > VRES -1 || x < 0 || y< 0))
		*(base +y*HRES +x) = color & 0xFF;
}


int get_pixel(int x, int y, char *base)
{
	if(x > HRES -1 || y > VRES -1 || x < 0 || y< 0)
		return -1;
	return (int)(*(base +y*HRES+x));
}


void clear_screen(char color, char *base)
{
	int x,y =0;
	for(;  y< VRES; y++){
		for(x =0; x < HRES; x++){
			set_pixel(x,y,color,base);
		}
	}
}


void draw_line(int xi, int yi, int xf, int yf, int color, char *base)
{
	if(!(xi > HRES-1 || xi < 0 || xf > HRES -1 || xf < 0|| 
			 yi > VRES-1 || yi < 0 || yf > VRES -1 || yf < 0))
	{
		double d;
		double dx,dy;
		double Eincr, NEincr;
		double yincr;
		double t;
		
		dx = abs(xi-xf);
		dy = abs(yi-yf);
		
		if(dy <= dx)
		{
			if(xf < xi)
			{
				t = xf; xf = xi; xi = t;
				t = yf; yf = yi; yi = t;
			}
			if(yf > yi)
				yincr = 1;
			else
				yincr = -1;
			d = 2*dy - dx;
			Eincr = 2*dy;
			NEincr = 2*(dy-dx);
			set_pixel(xi,yi,color,base);
			for(xi++;xi <= xf; xi++)
			{
				if(d < 0)
				 d+= Eincr;
				else
				{
					d += NEincr;
					yi += yincr;
				}
				set_pixel(xi,yi,color,base);
			}
		}
		else
		{
			if(yf < yi)
			{
				t = xf; xf = xi; xi = t;
				t = yf; yf = yi; yi = t;
			}
			if(xf > xi)
				yincr = 1;
			else
				yincr = -1;
			d = 2*dx-dy;
			Eincr=2*dx;
			NEincr = 2*(dx-dy);
			set_pixel(xi,yi,color,base);
				
			for(yi++; yi <= yf; yi++)
			{
				if(d < 0)
					d+= Eincr;
				else
				{
					d += NEincr;
					xi += yincr;
				}
				set_pixel(xi,yi,color,base);		
			}
		}	
	}
}


void draw_frame(int xi,int yi,int width, int height, char *base){
    int i,j;
    for(i = 0; i < height;i++){
        if(i < THICKNESS){//borda de cima
            for(j = 0; j < width; j++)
                set_pixel(xi+j,yi+i,BORDER_COLOR,base);
        }
        if(i >= THICKNESS && i <height -THICKNESS-1){//bordas dos lados
            for(j = 0; j < width;j++){
                if(j < THICKNESS)
                    set_pixel(xi+j,yi+i,BORDER_COLOR,base);
                if(j > width - THICKNESS-1)
                    set_pixel(xi+j,yi+i,BORDER_COLOR,base);
            }
        }
        else{
            for(j = 0; j < width;j++)
                set_pixel(xi+j,yi+i,BORDER_COLOR,base);
        }       
    }   
}


int get_h(){return HRES;};
int get_v(){return VRES;};



void drawIntAt(int num, int x, int y, int fore_color, int back_color,
				int char_scale, char *video_base, char *table)
{
	int i = 0;
	
	//se o numero for negativo, imprimir '-'
	if(num < 0)
	{
		drawCharAt('-', x, y, fore_color, back_color, char_scale, video_base, table);
		i++;
		num = 0 - num;
	}
	
	//descobrir a ordem de grandeza do numero
	int ordem = 1;
	while(num / ordem >= 10) ordem *= 10;
	
	//da esquerda para a direita, imprimir os algarismos
	while(true)
	{
		int digito = num / ordem;
		drawCharAt(digito + '0', x + 8 * char_scale * i, y, fore_color, back_color, char_scale, video_base, table);
		num -= digito * ordem;
		if(ordem == 1) break;
		ordem /= 10;
		i++;
	}
}


void drawStringAt(char* str, int x, int y, int fore_color, int back_color,
				int char_scale, char *video_base, char *table)
{
	int i = 0;
	while(str[i] != 0)
	{
		drawCharAt(str[i], x + 8 * char_scale * i, y, fore_color, back_color, char_scale, video_base, table);
		i++;
	}
}


void drawCharAt(char c, int x, int y, int fore_color, int back_color,
				int char_scale, char* video_base, char* table)
{
	// posiÁ„o do car·cter ìcî em ìtableî (lida de po.dat)
	char* char_def = table + c * CHR_H;

	int i, j;
	Byte mask = 0x80;
	int color;
	int x_act, y_act, sx, sy;
	// usar operadores bitwise para isolar e testar cada um dos bits
	for (j = 0, y_act = y; j < CHR_H; j++, y_act += char_scale) // for each character row
	{
		for (i = 0, x_act = x; i < 8; i++, x_act += char_scale)		// for each pixel in row
		{
			color = (*char_def & (mask >> i)) ? fore_color : back_color;
			if (color == -1) continue;
			for(sx = 0; sx < char_scale; sx++)
					for(sy = 0; sy < char_scale; sy++)
						set_pixel(x_act + sx, y_act + sy, color, video_base);
		}
		char_def++;
	}
}




void clear_partial_screen(int xi, int yi, int xf, int yf,char*base){
    int i,j;
    for(i = 0; yi+i <= yf;i++)
        for(j=0;xi+j<=xf;j++)
            set_pixel(xi+j,yi+i,0,base);
}

void clean_red(char* base){
    int i,j;
    for(i = 156; i < VRES; i++)
        for(j=0; j < HRES;j++){
            if(get_pixel(j,i,base) == RED_COLOR)
                set_pixel(j,i,BORDER_COLOR,base);
        }
    
}

int count_pixels(int xi,int yi,int xf, int yf,int color,char* base){
    int count = 0;
    int i =0;
    int k = 0;
    for(i =  yi; i < yf; i++)
        for(k = xi; k < xf; k++){
            if(get_pixel(xi+k,yi+i,base) == color)
                count++;
        }
    
    return count;
}



